package tv.dyndns.kishibe.server;

import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.openid4java.OpenIDException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.ax.FetchRequest;

import com.google.common.base.Preconditions;

/**
 * Servlet implementation class OpenIdRequestServlet
 */
@SuppressWarnings("serial")
public class OpenIdRequestServlet extends HttpServlet {
	private static final String REDIRECT_URL = "http://kishibe.dyndns.tv:8080/QMAClone/";
	private static final Logger logger = Logger.getLogger(OpenIdRequestServlet.class.toString());
	private static final String RETURN_TO_URL = "http://kishibe.dyndns.tv:8080/QMAClone/openid_response";
	private static final String END_POINT = "https://www.google.com/accounts/o8/id";
	private final ConsumerManager consumerManager;

	public OpenIdRequestServlet(ConsumerManager consumerManager) {
		this.consumerManager = Preconditions.checkNotNull(consumerManager);
	}

	protected void doGet(HttpServletRequest httpReq, HttpServletResponse httpResp)
			throws ServletException, IOException {
		try { // perform discovery on the user-supplied identifier
			@SuppressWarnings("rawtypes")
			List discoveries = consumerManager.discover(END_POINT);

			// attempt to associate with the OpenID provider
			// and retrieve one service endpoint for authentication
			DiscoveryInformation discovered = consumerManager.associate(discoveries);

			// store the discovery information in the user's session
			httpReq.getSession().setAttribute("openid-disc", discovered);

			// obtain a AuthRequest message to be sent to the OpenID provider
			AuthRequest authReq = consumerManager.authenticate(discovered, RETURN_TO_URL);

			// Attribute Exchange example: fetching the 'email' attribute
			FetchRequest fetch = FetchRequest.createFetchRequest();
			fetch.addAttribute("email",
			// attribute alias
					"http://schema.openid.net/contact/email", // type URI
					true); // required

			// attach the extension to the authentication request
			authReq.addExtension(fetch);

			if (!discovered.isVersion2()) {
				// Option 1: GET HTTP-redirect to the OpenID Provider endpoint
				// The only method supported in OpenID 1.x
				// redirect-URL usually limited ~2048 bytes
				httpResp.sendRedirect(authReq.getDestinationUrl(true));
			} else {
				// Option 2: HTML FORM Redirection (Allows payloads >2048 bytes)

				RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(
						"formredirection.jsp");
				httpReq.setAttribute("parameterMap", authReq.getParameterMap());
				httpReq.setAttribute("destinationUrl", authReq.getDestinationUrl(false));
				dispatcher.forward(httpReq, httpResp);
			}
		} catch (OpenIDException e) {
			String message = "OpenIDによる認証に失敗しました";
			logger.log(Level.WARNING, message);
			responseRequest(httpResp, message);
		}
	}

	private void responseRequest(HttpServletResponse response, String message) throws IOException {
		response.sendRedirect(REDIRECT_URL);
		response.setContentType("text/plain");
		response.setCharacterEncoding("utf-8");

		try (ServletOutputStream outputStream = response.getOutputStream()) {
			outputStream.write(message.getBytes("utf-8"));
		}
	}
}
